package wortubung;

import static wortubung.util.CommonUtils.isEmpty;
import static wortubung.util.CommonUtils.makeLine;
import static wortubung.util.CommonUtils.neverNull;
import wortubung.util.CommonUtils;

public enum WortUbungCommand {
	__STUDY         ("Commands for interactive studying and basic operations:"),
	CMD_LANG        ("lang",                true , "[<language>]", "Set the current language, e.g., 'de' or 'German' (without quotes)."),
	CMD_DEF         ("def",                 true , "<text_pattern>", "Search words with that pattern in the definition. (For patterns, see below.)"),
	CMD_QUIZ        ("quiz",                true , "<quiz_option>*|-?", "Run an interactive quiz. -? shows quiz options."),
	CMD_LIST        ("list",                true , "<list_name>*", "Display the words in the list."),
	CMD_PIPE        ("pipe",                false, "[<file_name>|off|clear]", "Start or stop piping subsequent actions into a file. Default file: \"wu.log\".|" +
	                                               "Without value, enable piping with the current pipe file.|" +
			                                       "Specify 'off' to turn off piping.|" +
	                                               "Specify 'clear' to delete the content of the current pipe file."),
	CMD_LATEST      ("latest",              true , "(-sort|-simple)*", "Print the recently visited words; 'simple' prints one word per line."),
    CMD_PAGE_WIDTH  ("pagewidth",  "pw",    true , "[<page_width>]", "Set the page width. Without value, the current value is displayed."),
    CMD_CLIPBOARD   ("clipboard",  "cb",    false, "<anything>|\\", "Copy the text to the clipboard.|For \\, copy multiple lines of text; a single '.' terminates."),
    CMD_STATS       ("stats",               true , null, "Show general statistics about the dictionary."),
    CMD_QUIT        ("q",                   false, null, "Quit the shell."),
    CMD_HELP        ("?",                   false, null, "This help screen."),

    __STUDY_OFF_LINE("Commands for off-line studying:"),
    CMD_PRINT       ("print",               true , "<print_option>*|-?", "Print the words with the current criteria. -? shows print options."),
    CMD_GEN_QUIZ    ("genquiz",             false, "<quiz_option>*|-?", "Generate quiz. -? shows quiz genaration options."),
    CMD_SCORE_QUIZ  ("scorequiz",           true , "<quiz_file>", "To score the answers in the quiz file."),
    CMD_FILL_BLANK  ("fillblank",           true , "[<list_name>*]", "Print distinct word prefices followed by a blank to fill in as an exercise."),
    CMD_PREFIX_COUNT("prefixcount",         true , "[<list_name>*]", "Count the distinct prefices of words in the lists or all."),

    __STUDY_ON_LINE ("Commands for studying:"),
    CMD_DAILY       ("daily",               true , "<YYYY-MM-DD>*|list <YYYY[-MM]>*", "Print daily sentences for the day (if specified) or today.|" +
    		 									   "The 'list' shows all the numbers of each day.|" +
    		 									   "(Year and/or can be omitted for the current year.)"),
//    CMD_NUMBER      ("number",     "num",   true , "<digits['|.digits]>", "Print the number in words of the current language; the apostrophe indicates ordinal."),
//    CMD_DATE        ("date",                true , "<[YYYY-]MM-DD>", "Print the date in words of the current language"),
//    CMD_TIME        ("time",                true , "<HH:MM:SS>", "Print the time in words of the current language"),
    CMD_SHOW        ("show",                true, "seasons|weekdays|months", "List season, weekday or month names in available languages."),

    __LANG_SPECIFIC ("Commands for particular language studying:"),
    CMD_CONJUG      ("conjug",     "j",     true , "<verb>*", "Conjugate verbs of the current language."),
    CMD_CONJUG_X    ("conjugx",    "jx",    true , "<verb>*", "Fetch the conjugation of verbs from an external source, if available."),
    CMD_UNCONJUG    ("unconjug",   "uj",    true , "<word>*", "Unconjugate the irregular verbs of the current language."),
    CMD_DECLINE     ("decline",    "decl",  true , "[<word_def>]", "Decline a noun or pronoun of the current language."),
    CMD_COMPARATIVE ("comparative","comp",  true , "<adj_adv>*", "List comparative and superlative of adjectives and adverbs."),
    CMD_SPECIAL_CONJ("sj",                  true , null, "List all verbes of special conjugation of the current language."),

    __MANAGING      ("Commands for managing word lists:"),
    CMD_LIST_INFO   ("listinfo",            true , "<list_name>* [-csv]", "Print the information about the specified or all lists."),
    CMD_LIST_PREFIX ("listprefix", "listp", true , null, "Print distinct prefices and the lists that contain them."),
    CMD_LIST_EDIT   ("listedit",   "ed",    true , "(<list_name>|<prefix>)*", "Edit the specified lists and lists that contain the prefices."),
    CMD_EDITOR      ("editor",              true , "[<editor_name>]", "Set editor. Without value, the current editor is displayed."),
    CMD_RELOAD      ("reload",              true , null, "Reload the external word lists."),
    CMD_VERBOSE     ("verbose",             false, "on|off", "Turn on or off verbose mode. Without value, the current value is displayed."),

    __INTERNAL      ("Commands for development uses:"),
    _INSPECT        ("inspect",             true , "<list_name>*", "Inspect the specified or all word lists."),
    _FORMAT         ("format", "fmt",       false, "json|default", "Output for programming uses. Up to individual commands to observe."),
    _DEBUG          ("debug"),
    _UNKNOWN        (null),
    _WORDS          (null);
	
	String cmd1;
	String cmd2;
	public boolean isPiped;
	public String paramsDesc;
	public String description;

	public static int maxDisplayLen;
	public static int maxParamsDescLen;

	static {
		maxDisplayLen = 9;
		maxParamsDescLen = 13;
		for (WortUbungCommand c : values()) {
			if (c.name().startsWith("_"))
				continue;
			int len = c.cmd2 == null ? (c.cmd1 == null ? 0 : (c.cmd1.length() + 1)) : (c.cmd1.length() + c.cmd2.length() + 2);
			if (len > maxDisplayLen)
				maxDisplayLen = len;
			len = CommonUtils.length(c.paramsDesc);
			if (len > maxParamsDescLen)
				maxParamsDescLen = len;
		}
	}

	private WortUbungCommand(String command, boolean isPiped, String paramsDesc, String description) {
		this(command, null, isPiped, paramsDesc, description);
	}

	private WortUbungCommand(String cmd1, String cmd2, boolean isPiped, String paramsDesc, String description) {
		this.cmd1 = cmd1;
		this.cmd2 = cmd2;
		this.isPiped = isPiped;
		this.paramsDesc = CommonUtils.neverNull(paramsDesc);
		this.description = description;
	}
	private WortUbungCommand(String name) { this(name, false, null, null); }

	boolean isInternal() { return name().startsWith("_") && !isCategory(); }
	boolean isCategory() { return name().startsWith("__"); }
	boolean match(String cmd) { return cmd1 != null && cmd1.equals(cmd) || cmd2 != null && cmd2.equals(cmd); }

	String getCommandDisplay() {
		if (cmd1 == null)
			return null;
		if (cmd2 != null)
			return "/" + cmd1 + '|' + cmd2;
		return "/" + cmd1;
	}

	/**
	 * @return Object[2] of { String(params), WortUbungCommand }.
	 */
	public static Object[] checkCommand(String cmdline) {
		Object[] ret = { null, WortUbungCommand._UNKNOWN };

		if (!cmdline.startsWith("/")) {
			ret[1] = WortUbungCommand._WORDS;
			return ret;
		}
		
		String cmd;
		int idx = cmdline.indexOf(' ');
		if (idx < 0) {
			cmd = cmdline.substring(1);
		} else {
			cmd = cmdline.substring(1, idx);
			ret[0] = cmdline.substring(idx+1).trim();
		}
		for (WortUbungCommand c : WortUbungCommand.values()) {
			if (c.match(cmd)) {
				ret[1] = c;
				break;
			}
		}
		return ret;
	}
    
    public static void showHelp(WortUbung wortUbung, String params) {

    	wortUbung.promptln(
    			"### For describing commands and parameters, regular expression syntax is used:       ###\n" +
   	            "###   <...> denotes a descriptive term. | means OR. () groups expressions.           ###\n" +
	            "###   [] means optional. * means 0 or more occurrances. Anything else is used as-is. ###\n");

    	String fmt = "    %-" + WortUbungCommand.maxDisplayLen + "s %-" + WortUbungCommand.maxParamsDescLen + "s  %s";
    	String prefix = makeLine(' ', WortUbungCommand.maxDisplayLen + WortUbungCommand.maxParamsDescLen + 7);

    	wortUbung.promptln("Dictionary lookup:");
    	wortUbung.promptfln(fmt, "<word_pattern>", "", "List words that match the pattern. (For patterns, see below.)");

    	for (WortUbungCommand c : WortUbungCommand.values()) {
    		if (c.isInternal() && !"internal".equalsIgnoreCase(params) || isEmpty(c.cmd1))
    			continue;
    		if (c.isCategory()) {
    			wortUbung.promptln(c.description);
    		} else {
    			String[] lines = neverNull(c.description).split("\\|");
    			for (int i=0; i<lines.length; ++i) {
    				if (i == 0)
    					wortUbung.promptfln(fmt, c.getCommandDisplay(), c.paramsDesc, lines[0]);
    				else
    					wortUbung.promptln(prefix + lines[i]);
    			}
    		}
    	}

    	wortUbung.promptln("\n" +
    			 "        In word and text patterns, use * as wildcard to represent any number of any letters.\n" +
    	         "        For composite words with spaces, use underscore (_) for word separators (spaces).\n\n" +
    	         "        A number of input methods are supported. Type '/? input' to see their details.\n" +
    	         "        (To display in Windows console, run 'chcp 65001', and select a TrueType font.)\n");
    }
}
